package zdream.pmfield.stage.director;

import java.util.List;
import java.util.Objects;

import zdream.pmfield.data.foe.Type;

/**
 * @author Zdream
 * @date 2023-11-14
 * @since 0.0.1
 */
public abstract class FixPair {
	public final float weight;
	public byte fixRateLevel;

	private FixPair(float weight) {
		this.weight = weight;
	}

	public static FixPair of(Type attack, Type defense, float weight) {
		return new TypeFixPair(attack, defense, weight);
	}

	public static FixPair of(Type.TypeWithWeight attack, Type defense) {
		return new TypeFixPair(attack, defense);
	}

	public static FixPair ofDefender(float weight, byte level, String... defenseBuffs) {
		return FixPair.of(new String[0], defenseBuffs, weight, level);
	}

	public static FixPair ofAttacker(float weight, byte level, String... attackerBuffs) {
		return FixPair.of(attackerBuffs, new String[0], weight, level);
	}

	public static FixPair of(String[] attackerBuffs, String[] defenseBuffs, byte level) {
		return FixPair.of(attackerBuffs, defenseBuffs, 1, level);
	}

	public static FixPair of(String[] attackerBuffs, String[] defenseBuffs, float weight, byte level) {
		return new BuffFixPair(attackerBuffs, defenseBuffs, weight, level);
	}

	public static FixPair ofAttackerBuff(float weight, byte level, String... attackerBuffs) {
		return FixPair.of(attackerBuffs, new String[0], 1, level);
	}

	public static FixPair ofDefenseBuff(float weight, byte level, String... defenseBuffs) {
		return FixPair.of(new String[0], defenseBuffs, weight, level);
	}

	public static float fixedRateTotal(List<FixPair> pairs) {
		float level = 0f;
		for (FixPair pair : pairs) {
			if (pair.fixRateLevel == Type.TYPE_FIXED_RATE_LEVEL_IMMUNE && pair.weight > 0.5f) {
				return 0;
			}
			level += pair.fixRateLevel * pair.weight;
		}

		if (level > 0) {
			return (3 + level * 2) / 3;
		} else if (level < 0) {
			return 3 / (3 - level * 2);
		} else {
			return 1;
		}
	}

	public boolean isForType() {
		return false;
	}

	public boolean isForBuff() {
		return false;
	}

	public TypeFixPair asType() {
		throw new RuntimeException(getClass().getSimpleName() + " is not a " + TypeFixPair.class.getSimpleName());
	}

	public BuffFixPair asBuff() {
		throw new RuntimeException(getClass().getSimpleName() + " is not a " + BuffFixPair.class.getSimpleName());
	}

	public static class TypeFixPair extends FixPair {
		public final Type attack, defense;

		public TypeFixPair(Type attack, Type defense, float weight) {
			super(weight);
			this.attack = Objects.requireNonNull(attack);
			this.defense = Objects.requireNonNull(defense);
			this.fixRateLevel = attack.fixRate(defense);
		}

		public TypeFixPair(Type.TypeWithWeight attack, Type defense) {
			super(attack.weight / (float) Type.TypeWithWeight.WEIGHT_FULL);
			this.attack = Objects.requireNonNull(attack.type);
			this.defense = Objects.requireNonNull(defense);
			this.fixRateLevel = attack.type.fixRate(defense);
		}

		@Override
		public boolean isForType() {
			return true;
		}

		@Override
		public TypeFixPair asType() {
			return this;
		}
	}

	public static class BuffFixPair extends FixPair {
		public final String[] attackBuffs;
		public final String[] defenseBuffs;

		public BuffFixPair(String[] attackBuffs, String[] defenseBuffs, float weight, byte level) {
			super(weight);
			this.attackBuffs = Objects.requireNonNull(attackBuffs);
			this.defenseBuffs = Objects.requireNonNull(defenseBuffs);
			this.fixRateLevel = level;
		}

		@Override
		public boolean isForBuff() {
			return true;
		}

		@Override
		public BuffFixPair asBuff() {
			return this;
		}
	}
}
